package actions

import (
	"encoding/json"
	"errors"
	"github.com/jordan-wright/email"
	"io"
	"io/ioutil"
	"jdsd/model"
	"log"
	"net/http"
	"net/smtp"
	"net/textproto"
	"net/url"
	"strconv"
	"strings"
	"time"
)

func GetHeader() http.Header {
	var headers = map[string]string{
		"Connection":      "keep-alive",
		"referer":         "https://servicewechat.com/wxb78a5743a9eed5bf/17/page-frame.html",
		"xweb_xhr":        "1",
		"user-agent":      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF XWEB/6763",
		"Content-Type":    "application/x-www-form-urlencoded",
		"Accept":          "*/*",
		"Accept-Language": "zh-CN,zh",
	}
	var header = http.Header{}
	for k, v := range headers {
		header.Add(k, v)
	}
	return header
}
func GetReq(params map[string]string, method string) *http.Request {
	data := url.Values{}
	for key, value := range params {
		data.Set(key, value)
	}
	req, err := http.NewRequest(method, "https://jdsd.gzhu.edu.cn/coctl_gzhu/index_wx.php", strings.NewReader(data.Encode()))
	if err != nil {
		log.Fatal(err)
	}
	req.Header = GetHeader()
	return req
}

func GetUserInfo(key string) (error, model.UserInfoRes) {
	client := &http.Client{}
	params := map[string]string{"route": "user_info", "key": key} // 将自定义的参数存入一个字典中
	req := GetReq(params, "POST")
	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	bodyText, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	userInfo := model.UserInfoRes{}
	err = json.Unmarshal(bodyText, &userInfo)
	if err != nil {
		log.Println("userinfo json failed; ", err)
	}
	if userInfo.Status != 1 {
		return errors.New("验证登录失败,key错误"), model.UserInfoRes{}
	}
	log.Printf("%s同学你好，目前的积分为：%s", userInfo.Re.UserName, userInfo.Re.Credits)
	return nil, userInfo
}

func SignIn(key string) {
	client := &http.Client{}
	params := map[string]string{"route": "signin", "key": key} // 将自定义的参数存入一个字典中
	req := GetReq(params, "POST")
	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	bodyText, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	res := model.SignInRes{}
	err = json.Unmarshal(bodyText, &res)
	if err != nil {
		log.Println("signInRes json failed; ", err)
	}
	if res.Status == 1 {
		log.Println("签到成功")
	}
}

func DailyTrain(key string) {
	client := &http.Client{}
	params := map[string]string{"route": "train_list_get", "key": key} // 将自定义的参数存入一个字典中
	req := GetReq(params, "POST")
	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	bodyText, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	queRes := model.QuestionsRes{}
	json.Unmarshal(bodyText, &queRes)
	//构造编号和"1"的数组发送完成每日一题
	trainId := queRes.Re.TrainID
	ans := make([][]string, 0)
	for _, question := range queRes.Re.QuestionBag {
		tmp := []string{"\"" + question.Num + "\"", "\"1\""}
		ans = append(ans, tmp)
	}
	var sb strings.Builder
	sb.WriteByte('[')
	for i, row := range ans {
		if i > 0 {
			sb.WriteString(",") // 在每个元素之间添加逗号
		}
		sb.WriteByte('[')
		line := strings.Join(row, ",")
		sb.WriteString(line)
		sb.WriteByte(']')
	}
	sb.WriteByte(']')
	result := sb.String()
	data := url.Values{}
	data.Set("route", "train_finish")
	data.Set("train_id", trainId)
	data.Set("train_result", result)
	data.Set("key", key)
	req2, err := http.NewRequest("POST", "https://jdsd.gzhu.edu.cn/coctl_gzhu/index_wx.php", strings.NewReader(data.Encode()))
	if err != nil {
		log.Fatal(err)
	}
	req2.Header = GetHeader()
	resp2, err := client.Do(req2)

	if err != nil {
		log.Fatal(err)
	}
	defer resp2.Body.Close()

	body, err := ioutil.ReadAll(resp2.Body)
	if err != nil {
		log.Fatal(err)
	}
	trainFinishRes := model.TrainFinishRes{}
	json.Unmarshal(body, &trainFinishRes)
	if trainFinishRes.Status == 1 {
		log.Println("每日一题完成!!")
	}
}

func Read(key string) {
	client := &http.Client{}
	params := map[string]string{"route": "classic_time", "key": key} // 将自定义的参数存入一个字典中
	var err error
	for i := 1; i <= 5; i++ {
		params["type"] = strconv.Itoa(i)
		params["addtime"] = "0"
		req1 := GetReq(params, "POST")
		_, err = client.Do(req1)
		params["addtime"] = "91"
		req2 := GetReq(params, "POST")
		_, err = client.Do(req2)
	}
	if err == nil {
		log.Println("每日阅读完成！！")
	}
}

/**
朴实无华的匹配函数, 先变换counter找到对手, 后150秒内每隔一秒发送心跳包
利用了一个bug, 在比赛结束后若继续发送心跳包, 会直接获得段位分和积分
但是段位分无上限, 容易造成段位分过高
这里判定了开始加分后, 会只执行五次加分操作
**/

type BaseRes struct {
	Status int `json:"status"`
}

func PK(key string) error {
	client := &http.Client{}
	params := map[string]string{"route": "get_counterpart", "key": key, "find_type": "0"} // 将自定义的参数存入一个字典中
	log.Println("匹配即将开始，需要花费一点时间")
	add := 0
	gameKey := ""
	for {
		i := 0
		params["counter"] = strconv.Itoa(i)
		req := GetReq(params, "POST")
		resp, err := client.Do(req)
		if err != nil {
			log.Fatal(err)
		}
		bodyText, err := io.ReadAll(resp.Body)
		if err != nil {
			log.Fatal(err)
		}
		pkRes := model.PKRes{}
		json.Unmarshal(bodyText, &pkRes)
		if pkRes.Status == 1 {
			gameKey = pkRes.QuestionBag.GamingKey
			break
		}
		i += 1
		if i > 10 {
			i = 0
		}

		resp.Body.Close()
	}
	log.Println("获取game_key")
	params = map[string]string{"route": "ask_opponent_score", "key": key, "gaming_key": gameKey} // 将自定义的参数存入一个字典中
	req := GetReq(params, "POST")
	for i := 0; i <= 150; i++ {
		time.Sleep(time.Second)
		resp, err := client.Do(req)
		if err != nil {
			log.Println(err)
			return err
		}
		bodyText, err := io.ReadAll(resp.Body)
		if err != nil {
			log.Println(err)
			return err
		}
		ackRes := model.AckRes{}
		json.Unmarshal(bodyText, &ackRes)
		if ackRes.Status == 2 {
			add++
		}
		if add >= 5 {
			break
		}
	}
	log.Println("每日匹配完成！！")
	return nil
}

func SendEmail(address string, content string) {
	host := "smtp.qq.com"
	port := ":25"
	userName := "your email@qq.com"
	password := "password" // qq邮箱填授权码

	e := &email.Email{
		To:      []string{address},
		From:    userName,
		Subject: "经典诵读每日通知",
		Text:    []byte(content),
		Headers: textproto.MIMEHeader{},
	}

	err := e.Send(host+port, smtp.PlainAuth("", userName, password, host))
	if err != nil {
		log.Println("发送邮件失败!! ", err)
		return
	}
	log.Println("邮件发送成功")
}
